package org.jcnc.IDEology.kernel.module;

import org.jcnc.IDEology.kernel.Module;
import org.jcnc.IDEology.kernel.kernel.Kernel;

import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * Represents a kernel module.
 */
public class KernelModule implements Module {
    private final Kernel kernel;

    /**
     * Enum representing the status of a module.
     */
    public enum ModuleStatus {
        REGISTERED,
        STARTED,
        STOPPED,
        ERROR
    }

    private final Map<String, ModuleStatus> moduleStatus;

    /**
     * Constructor for KernelModule.
     */
    public KernelModule() {
        kernel = new Kernel();
        moduleStatus = new HashMap<>();
    }

    /**
     * Registers a submodule.
     *
     * @param name            The name of the submodule.
     * @param module          The module to register.
     * @param startOnRegister Whether to start the module upon registration.
     */
    public void registerSubModule(String name, Module module, boolean startOnRegister) {
        kernel.registerModule(name, module);
        System.out.println("Registered module: " + name);
        if (startOnRegister) {
            module.startModule();
            moduleStatus.put(name, ModuleStatus.STARTED);
            System.out.println("Started module: " + name);

        } else {
            moduleStatus.put(name, ModuleStatus.REGISTERED);
        }
    }

    /**
     * Starts a submodule.
     *
     * @param name The name of the submodule.
     */
    public void startSubModule(String name) {
        Module module = kernel.getModule(name);
        if (module != null) {
            if (moduleStatus.get(name) == ModuleStatus.REGISTERED) {
                try {
                    module.startModule();
                    moduleStatus.put(name, ModuleStatus.STARTED);
                } catch (Exception e) {
                    moduleStatus.put(name, ModuleStatus.ERROR);
                    //handle error code

                }
            }
        } else {
            throw new NoSuchElementException("Module " + name + " does not exist.");
        }
    }

    /**
     * Stops a submodule.
     *
     * @param name The name of the submodule.
     */
    public void stopSubModule(String name) throws Exception {
        Module module = kernel.getModule(name);
        if (module != null) {
            if (moduleStatus.get(name) == ModuleStatus.STARTED) {
                module.stopModule();
                moduleStatus.put(name, ModuleStatus.STOPPED);
            }
        } else {
            throw new Exception("Module " + name + " does not exist.");
        }
    }

    /**
     * Prints all registered modules.
     */
    public void getAllRegisteredModules() {
        Set<String> moduleNames = kernel.getAllRegisteredModules();
        for (String moduleName : moduleNames) {
            System.out.println("----------------------------------------------");
            System.out.println("Module Name: " + moduleName);
            System.out.println("Module Status: " + moduleStatus.get(moduleName));
            System.out.println("----------------------------------------------");
        }
    }

    /**
     * Removes a submodule.
     *
     * @param name The name of the submodule.
     */
    public void removeSubModule(String name) throws Exception {
        Module module = kernel.getModule(name);
        if (module != null) {
            if (moduleStatus.get(name) == ModuleStatus.STARTED) {
                module.stopModule();
            }
            kernel.removeModule(name);
            moduleStatus.remove(name);
        } else {
            throw new Exception("Module " + name + " does not exist.");
        }
    }

    /**
     * Initializes a submodule.
     *
     * @param name The name of the submodule.
     */
    public void initSubModule(String name) {
        Module module = kernel.getModule(name);
        if (module != null) {
            module.initModule();
            System.out.println("Initialized module: " + name);
        } else {
            throw new NoSuchElementException("Module " + name + " does not exist.");
        }
    }

    /**
     * Registers a module with the kernel, and optionally starts it.
     *
     * @param name            The name of the module.
     * @param moduleClass     The class of the module.
     * @param startOnRegister If true, the module is started immediately after registration.
     */
    public void registerModule(String name, Class<? extends Module> moduleClass, boolean startOnRegister) {
        try {
            // Use reflection API to create a module instance
            Module module = moduleClass.getDeclaredConstructor(Kernel.class).newInstance(this.kernel);

            // Register the module
            this.kernel.registerModule(name, module);
            System.out.println("Registered module: " + name);

            if (startOnRegister) {
                module.startModule();
                this.moduleStatus.put(name, ModuleStatus.STARTED);
                System.out.println("Started module: " + name);
            } else {
                this.moduleStatus.put(name, ModuleStatus.REGISTERED);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Module getSubModule(String name) {
        return kernel.getModule(name);
    }

    /**
     * Gets the status of all modules.
     *
     * @return A map containing the name and status of each module.
     */
    public Map<String, ModuleStatus> getModuleStatus() {
        return this.moduleStatus;
    }

    /**
     * Initializes the module.
     */
    @Override
    public void initModule() {

    }

    /**
     * Starts the module.
     */
    @Override
    public void startModule() {
    }

    /**
     * Stops the module.
     */
    @Override
    public void stopModule() {
    }

}
